package com.example.dicomviewer.reconstruction;

import android.content.Context;
import android.opengl.GLSurfaceView;
import android.util.Log;
import android.view.MotionEvent;

import com.example.dicomviewer.core.DataArray;

/**
 * Created by Kiven on 2018/4/9.
 * Details:
 */

public class MyGLSurfaceView extends GLSurfaceView {
    private final MyGLRenderer renderer;

    float previousX, previousY;
    final static String TAG = "MyGLSurfaceView";

    int mode = 1;
    float preDistance = 0, distance = 0;

    float TOUCH_SCALE_FACTOR = 180.0f / 320;

    // 接受和 DataArray 中的visableCode标记相同的参数
    public void changeViewType(int visableCode) {
        DataArray.getInstance().changeVisibleByOrgan(visableCode);
        renderer.reloadTexure();
        requestRender();
    }

    public void reset() {
        DataArray.getInstance().reset();
        renderer.reloadTexure();
        requestRender();
    }

    // 一定注意这个函数每次触碰就会触发，所以尽量不要在其中定义变量
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        float x = event.getX();
        float y = event.getY();

        // 这个必须要放在这个函数里，放到外面就会变成(0,0)
        final int minLength = Math.min(getHeight(), getWidth());
        // 一定要注意此处的Masked，否则在安卓11上会有bug
        int act = event.getActionMasked();

        // 为了防止水平和竖直方向移动倍率不一致，实际上这个数值应当还和模型在视野中的范围有关
        switch (act) {
            case MotionEvent.ACTION_DOWN:
                this.mode = 1;
                break;
            case MotionEvent.ACTION_UP:
                this.mode = 0;
                break;
            case MotionEvent.ACTION_POINTER_UP:
                this.mode = 0;
                break;
            case MotionEvent.ACTION_POINTER_DOWN:
                preDistance = getDistance(event);
                Log.d(TAG, "<ACTION_POINTER_DOWN> preDistance: " + preDistance);
                if (preDistance > 10f) {
                    mode = 2;
                }
                break;
            case MotionEvent.ACTION_MOVE:
                if (this.mode == 1) {
                    float dx = x - previousX;
                    if (Math.abs(dx) < 5f) {
                        dx = 0;
                    }
                    float dy = y - previousY;
                    if (Math.abs(dy) < 5f) {
                        dy = 0;
                    }

                    // 水平方向？
                    double xAngle = dx / minLength * Math.PI;

                    // 竖直方向
                    double yAngle = dy / minLength * Math.PI;

                    Log.d(TAG, "<onTouchEvent>  dx: " + dx + "  , dy: " + dy);

                    double newAAngle = fixXAngle(renderer.getCameraAngle()[0] - xAngle);
                    double newBAngle = fixYAngle(renderer.getCameraAngle()[1] - yAngle);
                    renderer.setCameraAngle(newAAngle, newBAngle);

                    Log.d(TAG, "<onTouchEvent>  Angle: ( " + Math.toDegrees(renderer.getCameraAngle()[0]) + "° , " + Math.toDegrees(renderer.getCameraAngle()[1]) + "° )");
                    Log.d(TAG, "<onTouchEvent>  pos:   ( " + renderer.getCameraPos()[0] + " , " + renderer.getCameraPos()[1] + " , " + renderer.getCameraPos()[2] + " )");
                    Log.d(TAG, "<onTouchEvent>  dis form center : " + Math.sqrt(Math.pow(renderer.getCameraPos()[0], 2) + Math.pow(renderer.getCameraPos()[1], 2) + Math.pow(renderer.getCameraPos()[2], 2)));
                    renderer.setUp((float) newAAngle);

                    // 这个应该是平面顺时针逆时针旋转的问题
//                // reverse direction of rotation above the mid-line

                    // https://blog.51cto.com/u_3243911/1310615
                    // 下面这一段不明所以
//                    doublexAn=Math.toRadians(xAngl);
//                    doubleyAn=Math.toRadians(yAngle);
//                    floatx=(float)(30*Math.cos(xAn)*Math.sin(yAn));//求出旋转后的相机的X坐标
//                    floaty=(float)(30*Math.sin(xAn));
//                    floatz=(float)(30*Math.cos(xAn)*Math.cos(yAn));
//                    if(xAngl>90&&xAngl<270)//当旋转一定角度后要改变向上的方向，
//                        MatrixState.setCamera(x,y,z,0,0,0,0,-1,0);
//                    else
//                        MatrixState.setCamera(x,y,z,0,0,0,0,1,0);
//                    MatrixState.pushMatrix();

                    requestRender();
                } else if (mode == 2) {
                    distance = getDistance(event);
                    if (distance > 10f) {
                        // todo 关于缩放的调整算法，之后慢慢微调
                        Log.d(TAG, "distance: " + distance + " , preDistance " + preDistance + " , (Math.sqrt(2) * minLength : " + (Math.sqrt(2) * minLength + " , (distance - preDistance) / (Math.sqrt(2) * minLength): " + (distance - preDistance) / (Math.sqrt(2) * minLength)));
                        double scale = preDistance / distance;
                        renderer.setScale(renderer.getScale() / scale);
                        preDistance = distance;
                        requestRender();
                    }
                }
                break;
        }

        previousX = x;
        previousY = y;
        return true;
    }


    public MyGLSurfaceView(Context context) {
        super(context);
        // 创建一个OpenGL ES 3.0的上下文。
        setEGLContextClientVersion(3);

        renderer = new MyGLRenderer();
        // 将绘制用的渲染器设置给GLSurfaceView。
        setRenderer(renderer);
        // 只有当绘制数据变化时，才绘制/重绘视图。
        setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
//        setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
    }


    private float getDistance(MotionEvent event) {
        float x = event.getX(1) - event.getX(0);
        float y = event.getY(1) - event.getY(0);
        float distance = (float) Math.sqrt(x * x + y * y);//两点间的距离
        return distance;
    }

    // 修复仰角
    private static double fixYAngle(double angle) {
        double limit = Math.PI / 2f - 0.05f;
        if (angle >= limit) {
            angle = limit;
        }
        if (angle < -limit) {
            angle = -limit;
        }
        return angle;
    }

    // 修复左右视角
    private static double fixXAngle(double angle) {
        double limit = 2 * Math.PI;
        if (angle >= limit) {
            angle -= limit;
        }
        if (angle < -limit) {
            angle += limit;
        }
        return angle;
    }
}
